//侧边栏
function switch_sidebar() {
    let sidebar = document.getElementById("sidebar");
    let swbtn = document.getElementById("swbutton").childNodes[0];
    if (sidebar.style.display != "none") {
        sidebar.style.display = "none";
        swbtn.innerHTML = '>';
    } else {
        sidebar.style.display = "inline";
        swbtn.innerHTML = '<';
    }
}

/**************************
 * 必要的工具函数
 **************************/
/**
 * 球坐标距离计算
 * @param {number} latA 点A的纬度
 * @param {number} lngA 点A的经度
 * @param {number} latB 点B的纬度
 * @param {number} lngB 点B的经度
 * @returns 球面距离
 */
function distance(latA, lngA, latB, lngB) {
    var earthR = 6371000.; //地球半径
    var x = Math.cos(latA * Math.PI / 180.) * Math.cos(latB * Math.PI / 180.) * Math.cos((lngA - lngB) * Math.PI / 180);
    var y = Math.sin(latA * Math.PI / 180.) * Math.sin(latB * Math.PI / 180.);
    var s = x + y;
    if (s > 1) s = 1;
    if (s < -1) s = -1;
    var alpha = Math.acos(s);
    var dist = alpha * earthR;
    return dist;
}

/**
 * 角度计算
 * @param {*} bp1 点1
 * @param {*} bp2 点2
 * @returns 角度
 */
function calcAngle(bp1, bp2) {
    if (bp1 === undefined || bp2 === undefined) return 0;
    var x = Math.sin(bp2.lng - bp1.lng) * Math.cos(bp2.lat);
    var y = Math.cos(bp1.lat) * Math.sin(bp2.lat) - Math.sin(bp1.lat) * Math.cos(bp2.lat) * Math.cos(bp2.lng - bp1.lng);
    var angle = Math.atan2(x, y) * 180 / Math.PI;
    return angle > 0 ? angle : angle + 360;
}

/** 
 * 时间戳转字符串
 * @param {number} timestamp 时间戳
 * @returns 时间字符串
*/
function TimeStamp2String(timestamp) {//时间戳转字符串
    ts = new Date(timestamp);
    let hour = ts.getHours(); if (hour < 10) hour = "0" + hour;
    let minute = ts.getMinutes(); if (minute < 10) minute = "0" + minute;
    let second = ts.getSeconds(); if (second < 10) second = "0" + second;
    return `${ts.getFullYear()}-${1 + ts.getMonth()}-${ts.getDate()} ${hour}:${minute}:${second}`;
}

/*********************************
 * 地图初始化
 *********************************/
var map = new BMap.Map("container", { mapType: BMAP_HYBRID_MAP });
var markers = [], locations = [];
var location_glitter_icons = [loadIcon(3), loadIcon(4)] // 用来实现靠近风机时图标闪烁的效果
var location_default_icons = (new BMap.Marker()).getIcon();
var show = []; //指示某个marker是否正在显示
var last_pos = []; //指示某个marker上次的位置
var marker_pars, marker_cnt;

/*********************************
 * location（静态目标）初始化
 *********************************/
var locInitIndex = 0;  //location加载计数器
var locInitTimer; //location加载定时器

function addLocationOnce() {//添加一个location
    const { point, label, location } = locations[locInitIndex];
    new BMap.Convertor().translate([point], 1, 5, function (data) {
        const p = data.points[0];
        location.setPosition(p);
        location.addEventListener("mouseover", () => location.setLabel(label));
        location.addEventListener("mouseout", () => map.removeOverlay(location.getLabel()));
        map.addOverlay(location);
    });
    locInitIndex++;
    if (locInitIndex >= locations.length) { //全部location加载完毕后，关闭定时器
        locInitTimer = window.clearInterval(locInitTimer);
    }
}

function initLocations() {//添加所有location
    fetch("/api/locations").then(res => res.json()).then(result => {
        if (result.success && result.data != undefined) {
            //将获取到的location信息转换成所需格式
            result.data.forEach(pos => {
                let point = new BMap.Point(Number(pos["Lng"]), Number(pos["Lat"]));
                let location = new BMap.Marker();
                location.animationTimer = null; // 闪烁动画定时器
                let lbname = pos["Name"] || String(i + 1);
                let label = new BMap.Label(lbname, { offset: new BMap.Size(0, -20) });
                locations.push({ point, location, label });
            });
            locInitTimer = self.setInterval("addLocationOnce()", 200);
        } else {
            throw new Error("获取失败!");
        }
    }).catch(err => {
        console.log("Location获取失败!");
    });
}

initLocations();

/*********************************
 * location（静态目标）靠近闪烁效果
 *********************************/
function updateLocationStyle(user_pos) {
    for (const { point, location, label } of locations) {
        if (distance(user_pos.lat, user_pos.lng, point.lat, point.lng) < 10) {
            location.icon_index = 0;
            if (location.animationTimer == null) {
                location.animationTimer = setInterval(function () {
                    location.setIcon(location_glitter_icons[location.icon_index]);
                    location.icon_index = (location.icon_index + 1) % location_glitter_icons.length;
                }, 1000)
            }
        }
        else {
            if (location.animationTimer != null) {
                clearInterval(location.animationTimer);
                location.animationTimer = null;
            }
            location.setIcon(location_default_icons);
        }
    }
}

/*********************************
 * marker（动态目标）初始化
 *********************************/
fetch("/api/markers").then(res => res.json()).then(
    result => {
        if (result.success && result.data != undefined) {
            marker_pars = result.data;
            marker_cnt = marker_pars.length;
            map.centerAndZoom(new BMap.Point(marker_pars[0]["InitLng"], marker_pars[0]["InitLat"]), 12);//这里没做坐标转换是偷懒了
            map.enableScrollWheelZoom(true);

            addMarkers(marker_pars, () => {
                update();
                TimerOn();
            });
        } else {
            throw new Error("加载失败！");
        }
    }
).catch(err => {
    document.getElementById("container_info").innerHTML = "加载失败！";
});

/*********************************
 * marker（动态目标）位置更新
 *********************************/
var gps_vals = new Array(10);

function updateOnce(idx, data) {//更新某个Marker
    //例子：32.1,N,118.6,E,20.10,M,101352,P
    if (gps_vals[idx] != undefined && gps_vals[idx]["timestamp"] == data["timestamp"]) return;
    let lat = data['lat'], lng = data['lng'];
    if (gps_vals[idx] === undefined) gps_vals[idx] = data;
    if (lat == -1 && lng == -1) {
        gps_vals[idx]["in_turbine"] = true;
    } else {
        gps_vals[idx] = data;
        gps_vals[idx]["in_turbine"] = false;
    }
    var tips = "暂无数据";
    if (new Date().getTime() - data["timestamp"] < 1000 * 60 * 60 * 4) {//消息未过期
        tips = `更新时间：\r\n${TimeStamp2String(data['timestamp'])}`;
        if (gps_vals[idx]["in_turbine"]) {
            tips += `\r\n信号消失，进入风机`;
        } else {
            tips += `\r\n东经：${lng}\r\n北纬：${lat}`;
            tips += `\r\n高度：${data['alt']}m`;
            var new_point = new BMap.Point(lng, lat);
            setMarkerAt(idx, new_point, calcAngle(last_pos[idx], new_point));
            updateLocationStyle(new_point);
        }
        if (data['pa'] != undefined) {
            tips += `\r\n气压：${data['pressure']}Pa`;
        }
    }
    document.getElementById(`marker_desc${idx}`).innerHTML = tips;
}

//更新所有marker
function update() {
    let uids_str = marker_pars.map(x => x["UID"]).join(",");
    fetch(`/api/query?uid=${uids_str}`).then(res => res.json()).then(result => {
        if (result.success) {
            for (let i = 0; i < marker_cnt; i++) {
                if (result.data[i] != undefined) updateOnce(i, result.data[i]);
            }
        } else {
            throw new Error("请求失败！");
        }
    }).catch(err => {
        console.log("请求失败！");
    });
}

//间隔5000ms定时更新
var CurrentTimerState = true, ResumeWhenVisible = true;
var periodicUpdateTimer; //定时更新器

function TimerOn() {//启动定时更新器
    TimerOff();
    periodicUpdateTimer = self.setInterval("update()", 5000);
    document.getElementById("doupd").style.display = 'none';
    document.getElementById("noupd").style.display = 'inline';
    CurrentTimerState = true;
}

function TimerOff() {//关闭定时更新器
    periodicUpdateTimer = window.clearInterval(periodicUpdateTimer);
    document.getElementById("doupd").style.display = 'inline';
    document.getElementById("noupd").style.display = 'none';
    CurrentTimerState = false;
}

document.addEventListener("visibilitychange", function () {//最小化时停止更新
    if (document.visibilityState === 'hidden') {
        ResumeWhenVisible = CurrentTimerState;
        TimerOff();
    } else {
        if (ResumeWhenVisible === true) TimerOn();
    }
}, false);

/********************** 
* 地图控制
***********************/
function loadIcon(index) {
    return new BMap.Icon("/images/markers.png", new BMap.Size(30, 60), {
        anchor: new BMap.Size(15, 30),
        imageOffset: new BMap.Size(0 - index * 30, 0)
    });
}
var isPanning = false;
function reCenter() {
    if (isPanning) return;
    isPanning = true;
    var slng = 0.0, slat = 0.0, cnt = markers.length, fcnt = 0;
    for (var i = 0; i < cnt; i++) {
        if (!show[i]) continue;
        fcnt++;
        var pos = markers[i].getPosition();
        slng += pos.lng;
        slat += pos.lat;
    }
    if (fcnt > 0) {
        map.panTo(new BMap.Point(slng / fcnt, slat / fcnt));
    }
    isPanning = false;
}
function hideMarker(idx) {
    document.getElementById("btnShow" + idx).style.display = "inline";
    document.getElementById("btnHide" + idx).style.display = "none";
    if (idx >= 0 && idx < markers.length) {
        map.removeOverlay(markers[idx]);
        show[idx] = false;
    }
}
function showMarker(idx) {
    document.getElementById("btnShow" + idx).style.display = "none";
    document.getElementById("btnHide" + idx).style.display = "inline";
    if (idx >= 0 && idx < markers.length) {
        map.removeOverlay(markers[idx]);
        map.addOverlay(markers[idx]);
        show[idx] = true;
    }
}
function addMarkers(marker_pars, then) {
    var pointArr = marker_pars.map(mk => new BMap.Point(mk["InitLng"], mk["InitLat"]));
    new BMap.Convertor().translate(pointArr, 1, 5, function (data) {
        marker_pars.forEach((mkp, i) => {
            let label = new BMap.Label(mkp["Name"], { offset: new BMap.Size(0, -20) });
            let mk = new BMap.Marker(data.points[i], { icon: loadIcon(mkp["IconID"]) });
            mk.setRotation(marker_pars[i]["InitAngle"]);
            mk.addEventListener("mouseover", () => mk.setLabel(label));
            mk.addEventListener("mouseout", () => map.removeOverlay(mk.getLabel()));
            markers.push(mk);
            show.push(true);
            last_pos.push(pointArr[i]);
            map.addOverlay(markers[markers.length - 1]);
        });
        reCenter();
        then();
    });
}
function setMarkerAt(idx, newPoint, newDirection) {
    if (markers.length <= idx) return;
    new BMap.Convertor().translate([newPoint], 1, 5, function (data) {
        map.removeOverlay(markers[idx]);
        markers[idx].setRotation(newDirection);
        markers[idx].setPosition(data.points[0]);
        last_pos[idx] = newPoint;
        if (show[idx]) {
            map.addOverlay(markers[idx]);
        }
    });
}